package stream;

import org.junit.Test;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author : DuJiabao
 * @Date : 2021/3/20 14:09
 * @Project : java_learning
 * @File : null.java
 * @Desc :
 */
public class StreamTest {
  @Test
  public void test() {
    List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
    Stream<Integer> stream = integers.stream();
    stream.forEach(System.out::println);

    Stream<Integer> parallelStream = integers.parallelStream();
    parallelStream.forEach(System.out::println);  // 输出并不会按顺序哦！
  }

  @Test
  public void test2() {
    int[] ints = {1, 2, 3, 4};
    IntStream stream = Arrays.stream(ints);
    stream.forEach(System.out::println);

    double[] doubles = {1.0, 2.0, 3.0, 4.0};
    DoubleStream doubleStream = Arrays.stream(doubles);
    doubleStream.forEach(System.out::println);
  }

  @Test
  public void test3() {
    Stream<Integer> stream = Stream.of(1, 2, 3);  // 内部还是调用Arrays.stream()方法
    stream.forEach(System.out::println);
  }

  @Test
  public void test4() {
    Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2);
    stream.limit(10).forEach(System.out::println);
  }

  @Test
  public void test5() {
    Stream<Integer> stream = Stream.generate(() -> 1);
    stream.limit(10).forEach(System.out::println);
  }

  @Test
  public void test6() {
    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(0, new BigDecimal(10000), "Amy"));
    employees.add(new Employee(1, new BigDecimal(9000), "John"));
    employees.add(new Employee(3, new BigDecimal(8000), "Jerry"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));

    employees.stream()
            .filter((e) -> e.getSalary().compareTo(new BigDecimal(8000)) > 0)
            .forEach(System.out::println);
  }

  @Test
  public void test7() {
    List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 2, 6, 7, 8);
    Stream<Integer> stream = integers.stream();
    stream.distinct().forEach(System.out::println);
  }

  @Test
  public void test8() {
    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(0, new BigDecimal(10000), "Amy"));
    employees.add(new Employee(1, new BigDecimal(9000), "John"));
    employees.add(new Employee(3, new BigDecimal(8000), "Jerry"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));

    employees.stream()
            .distinct()
            .forEach(System.out::println);
  }

  @Test
  public void test9() {
    List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Stream<Integer> stream = integers.stream();
    stream.skip(3).forEach(System.out::println);  // 跳过前三个
  }

  @Test
  public void test10() {
    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(0, new BigDecimal(10000), "Amy"));
    employees.add(new Employee(1, new BigDecimal(9000), "John"));
    employees.add(new Employee(3, new BigDecimal(8000), "Jerry"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));

    employees.stream()
            .map(Employee::getName)   // 类名::方法名
            .forEach(System.out::println);
  }

  @Test
  public void test11() {
    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(0, new BigDecimal(10000), "Amy"));
    employees.add(new Employee(1, new BigDecimal(9000), "John"));
    employees.add(new Employee(3, new BigDecimal(8000), "Jerry"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));

    employees.stream()
            .mapToInt(Employee::getId)   // 类名::方法名
            .forEach(System.out::println);
  }

  @Test
  public void test12() {
    Employee[][] employees = {
            {new Employee(0, new BigDecimal(10000), "Amy"), new Employee(1, new BigDecimal(9000), "John")},
            {new Employee(3, new BigDecimal(8000), "Jerry")},
            {new Employee(2, new BigDecimal(7000), "Taylor"), new Employee(4, new BigDecimal(6000), "Swift")}
    };

    Arrays.stream(employees).flatMap(Arrays::stream).forEach(System.out::println);  // 针对每个一维数组，也通过Arrays.stream进行转换
    Arrays.stream(employees)
            .flatMap((es) -> Arrays.stream(es).map(Employee::getName))  // 针对每个一维数组，再转换成stream，并使用映射
            .forEach(System.out::println);
  }

  @Test
  public void test13() {
    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(0, new BigDecimal(10000), "Amy"));
    employees.add(new Employee(1, new BigDecimal(9000), "John"));
    employees.add(new Employee(3, new BigDecimal(8000), "Jerry"));
    employees.add(new Employee(2, new BigDecimal(7000), "Taylor"));
    // Comparator.comparing(Employee::getSalary)表示获取一个通过salary排序的比较器
    Stream<Employee> sorted = employees.stream().sorted(Comparator.comparing(Employee::getSalary));
    //Stream<Employee> sorted = employees.stream().sorted((o1, o2) -> o1.getSalary().compareTo(o2.getSalary()));  // 前后等效
    sorted.forEach(System.out::println);
  }

  @Test
  public void test14() {
    List<Integer> integers = Arrays.asList(4, 58, 6, 4, 33, -8, -7, -10);
    integers.stream().sorted().forEach(System.out::println);   // 使用自然排序的条件是比较的类型是基本数据类型或者是已经实现了Comparable接口
  }

  @Test
  public void test15() {
    List<Integer> integers = Arrays.asList(4, 58, 6, 4, 33, -8, -7, -10);
    Stream<Integer> stream = integers.stream();

    boolean res = stream.allMatch((x) -> x > 0);
    System.out.println(res);  // false

    stream = integers.stream();
    res = stream.anyMatch((x) -> x > 0);  // true
    System.out.println(res);

    stream = integers.stream();
    res = stream.noneMatch((x) -> x <= 0);  //false
    System.out.println(res);

    stream = integers.stream();
    Optional<Integer> first = stream.sorted().findFirst();  // 获取第一个
    Integer integer;
    if (first.isPresent()){
      integer = first.get();
      System.out.println(integer);  // -10
    }

    stream = integers.stream();
    Optional<Integer> any = stream.findAny();   // 随便选一个，但不随机
    if (any.isPresent()) {
      integer = any.get();
      System.out.println(integer);
    }

    stream = integers.stream();
    long count = stream.count();  // 计数
    System.out.println(count);

    stream = integers.stream();
    Optional<Integer> max = stream.max(Integer::compareTo);  // 求最大值
    if (max.isPresent()) {
      integer = max.get();
      System.out.println(integer);
    }

    stream = integers.stream();
    Optional<Integer> min = stream.min(Integer::compareTo);  // 求最小值
    if (min.isPresent()) {
      integer = min.get();
      System.out.println(integer);
    }

    stream = integers.stream();
    Optional<Integer> reduce = stream.reduce(Integer::sum);  // 可以将流中元素反复结合起来，得到一个值。求和！
    if (reduce.isPresent()) {
      integer = reduce.get();
      System.out.println(integer);
    }

    stream = integers.stream();
    List<Integer> collect = stream.collect(Collectors.toList());
    System.out.println(collect);

    stream = integers.stream();
    Set<Integer> collect1 = stream.collect(Collectors.toSet());
    System.out.println(collect1);

    List<String> strings = Arrays.asList("1", "2", "3");
    Stream<String> stream1 = strings.stream();
    String collect2 = stream1.collect(Collectors.joining());  // 将String合并成一个字符串，默认通过空格分隔，可以输入分隔符
    System.out.println(collect2);
  }

  @Test
  public void test16() {
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 100000000; i++) {
      list.add(i);
    }

    Instant start = Instant.now();
    int sum = list.stream().parallel().mapToInt(x -> x).sum();
    //sum = list.parallelStream().mapToInt(x -> x).sum();
    Instant end = Instant.now();
    System.out.println(sum);
    System.out.println("花费时间" + Duration.between(end, start));
  }

  @Test
  public void test17() {
  }
}
